package com.jvm.classfile.model;

import com.jvm.Utils;
import lombok.Data;

import java.util.Objects;

/**
 * @program: diy_simple_jvm
 * @description:
 * @author: CaoYong
 * @create: 2021-07-08 19:02
 **/
@Data
public class Class {


    ClassFile classFile;

    public int stat;
    String name;
    Class superClass;
    Method[] methods;
    Field[] fields;

    public Class(ClassFile classFile, String name, Class superClass, Method[] methods) {
        this.classFile = classFile;
        this.name = name;
        this.superClass = superClass;

        if (this.methods != null) {
            for (Method method : methods) {
                method.clazz = this;
            }
        }
    }

    public Class(String name, Class superClass, Field[] fields, Method[] methods, ClassFile classFile) {
        this.name = name;
        this.superClass = superClass;
        this.fields = fields;
        this.methods = methods;
        this.classFile = classFile;

        if (fields != null) {
            for (Field field : fields) {
                field.clazz = this;
            }
        }

        if (methods != null) {
            for (Method method : methods) {
                method.clazz = this;
            }
        }
    }

    public Method getSpecialStaticMethod(String name, String descriptor) {
        for (Method method : methods) {
            if(!Utils.isStatic(method.getAccessFlags())) {
                continue;
            }
            if (Objects.equals(name, method.name) && Objects.equals(descriptor, method.getDescriptor())) {
                return method;
            }
        }
        return null;
    }

    /**
     * 获取静态方法, 递归寻找
     * @param name 方法名
     * @param descriptor 方法描述符
     * @return return null if not matchable
     */
    public Method getStaticMethod(String name, String descriptor) {
        final Method method = this.getSpecialStaticMethod(name, descriptor);
        if (method != null) {
            return method;
        }
        if (superClass == null) {
            return null;
        }
        return this.superClass.getStaticMethod(name, descriptor);
    }

    /**
     * 获取静态字段，递归寻找
     * @param name 字段名
     * @param descriptor 字段描述符
     * @return return null if not matchable
     */
    public Field getStaticField(String name, String descriptor) {
        for (Field field : fields) {
            if (!Utils.isStatic(field.getAccessFlag())) {
                continue;
            }
            if (Objects.equals(name, field.name) && Objects.equals(descriptor, field.descriptor)) {
                return field;
            }
        }

        if (superClass == null) {
            return null;
        }
        return this.superClass.getStaticField(name, descriptor);
    }

    public Instance newInstance() {

        // 实例字段复制
        final Field[] newFields = new Field[fields.length];
        for (int i = 0; i < newFields.length; i++) {
            final Field field = fields[i];
            Field newField;
            if (Utils.isStatic(field.getAccessFlag())) {
                newField = field; // 静态字段复制引用
            } else {
                // 非静态字段复制内容，并且初始化
                newField = new Field(field.getAccessFlag(), field.name, field.descriptor);
                newField.init();
            }
            newFields[i] = newField;
        }

        final Instance instance = new Instance(this);
        if (this.superClass != null) {
            instance.superInstance = this.superClass.newInstance();
        }
        return instance;
    }

    /**
     * 在当前类获取非静态方法
     */
    public Method getSpecialMethod(String name, String descriptor) {
        for (Method method : methods) {
            if (Utils.isStatic(method.accessFlags)) {
                continue;
            }

            if (method.name.equals(name) && method.descriptor.equals(descriptor)) {
                return method;
            }
        }
        return null;
    }
}
